#include "ConcuShare.h"

#include "lib/signals/SIGTERM_Handler.h"
#include "util/definitions.h"
#include "util/Log.h"


#include <wait.h>

ConcuShare::ConcuShare(): fileServer(getpid()), shared(getpid()) {
	console= new Console(this);
	quit = false;
	master_pid= getpid();
	server_pid = -1;
}

ConcuShare::~ConcuShare() {
	delete console;
}

void ConcuShare::start_application() {
	int pid= fork();
	if(pid == 0) {
		start_server();
	} else {
		server_pid = pid;
		list_pids.push_back(server_pid);
		start_console();
	}
}

void ConcuShare::start_server() {
	Log::getInstance().log(getpid(), ">> Server iniciado en proceso: ");
	fileServer.startServer();
	Log::getInstance().log(getpid(), ">> Fin de un proceso server ");
}

void ConcuShare::start_console() {
	console->show_inicio();

	while(!quit && (getpid() == master_pid))
		console->show_shell();

	if(getpid() == master_pid) {

		Log::getInstance().log(getpid(), ">> Esperando a mis hijos, si no terminaron");
		while (! list_pids.empty())
		{
			int ret = 0;
			Log::getInstance().log(getpid(), ">> Esperando a " + list_pids.front());
			waitpid(list_pids.front(),&ret,0);
			list_pids.pop_front();
		}
		console->show_bye();
	}
}

void ConcuShare::stop_application() {
	quit = true;
	if ( server_pid > 0 )
		fileServer.stopServer(server_pid);
}

void ConcuShare::share_file(const std::string& path) {
	if(path.empty() || !file_exist(path)) {
		console->show_error("Ingrese un archivo existente.");
		return;
	}

	int pid= fork();
	if(pid == 0) {
		std::clog << ">> Inicio proceso hijo: " << getpid() << std::endl;
		Log::getInstance().log(getpid(), ">> Inicio proceso hijo: ");
		std::cout << ">> Archivo a compartir: " << path << std::endl;
		std::string file(path);
		shared.shareFile(file);
		std::cout << ">> Archivo: " << path << " compartido." << std::endl;
	}else{
		list_pids.push_front(pid);
	}
}

void ConcuShare::unshare_file(unsigned int num_file) {
	SharedFileList shared_files;
	shared.getMySharedFiles(shared_files);
	if( num_file >= shared_files.getSize() || num_file < 0 )  {
		console->show_error("Seleccione un numero de archivo valido.");
		return;
	}

	int pid= fork();
	if(pid == 0) {
		Log::getInstance().log(getpid(), ">> Inicio proceso hijo: ");
		std::string path= shared_files.getFileName(num_file);
		std::cout << ">> Archivo a descompartir: " << path << std::endl;
		shared.unshareFile(path);
		std::cout << ">> Archivo: " << path << " descompartido." << std::endl;
	} else {
		list_pids.push_front(pid);
	}
}

void ConcuShare::download_file(unsigned int num_file) {
	SharedFileList shared_files;
	shared.getAllSharedFiles(shared_files,true);
	if( num_file >= shared_files.getSize() || num_file < 0 ) {
		console->show_error("Seleccione un numero de archivo valido.");
		return;
	}

	if ( shared_files.getUserID(num_file) != fileServer.getUserID() ) //checkeo que no sea mio el archivo
	{
		int pid= fork();
		if(pid == 0) {

			Log::getInstance().log(getpid(), ">> Inicio proceso hijo: ");
			std::string path= shared_files.getFileName(num_file);
			std::cout << ">> Archivo a descargar: " << path << std::endl;
			bool result = fileServer.downloadFile(path, shared_files.getUserID(num_file));
			if ( result )
				std::cout << ">> Archivo: " << path << " descargado." << std::endl;
			else
				std::cout << ">> Error al descargar el archivo: " << path<< std::endl;
		} else {
			list_pids.push_front(pid);
		}
	}
	else
		console->show_error("No se puede descargar un archivo propio.");
}

const std::list<std::string>& ConcuShare::get_files_shared() {
	SharedFileList shared_files;
	shared.getAllSharedFiles(shared_files,true);
	create_files_list(shared_files, true);
	return list_files_shared;
}

const std::list<std::string>& ConcuShare::get_my_files_shared() {
	SharedFileList shared_files;
	shared.getMySharedFiles(shared_files);
	create_files_list(shared_files, false);
	return list_files_shared;
}

bool ConcuShare::file_exist(const std::string &path) {
	bool exist= false;
	std::fstream file;
	file.open(path.c_str(), std::ios::in);
	if(file.is_open())
		exist= true;
	return exist;
}

void ConcuShare::create_files_list(SharedFileList& shared_files, bool with_id) {
	int count= 0;
	int id= 0;

	list_files_shared.clear();

	for(unsigned int i= 0; i < shared_files.getSize(); ++i) {

		std::string filename, str_id, str_count, information;

		++count;
		intToString(count, str_count);
		filename= shared_files.getFileName(i);

		if(with_id) {
			id = shared_files.getUserID(i);
			intToString(id, str_id);
			information= str_count + " " + str_id + "    " + filename;
		} else
			information= str_count + "    " + filename;

		list_files_shared.push_front(information);
	}
}


